<?php

namespace App\Library;

use Carbon\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
use Jenssegers\Agent\Agent;

class NginxLog
{
    private string $filePath;

    /**
     * @param string $filePath
     * @return static
     */
    public static function init(string $filePath = ''): static
    {
        return $filePath ? (new static)->setFilePath($filePath) : new static;
    }

    /**
     * @param string $filePath
     * @return static
     */
    public function setFilePath(string $filePath): static
    {
        if ($filePath && File::exists($filePath)) {
            $this->filePath = $filePath;
        }
        return $this;
    }

    /**
     * @return Collection
     */
    public function get(): Collection
    {
        if (!empty($this->filePath)) {
            $collect = collect(explode("\n", File::get($this->filePath)));
            return $collect->filter(function ($value) {
                return $value !== '';
            })->map(function ($item) {
                $keywords = preg_split("/[\"*]/", Str::replaceArray('- ', [''], $item));
                $arr = $this->withData($keywords);
                $arr['string'] = $item;
                return array_filter($arr);
            })->reverse()->values();
        }
        return collect();
    }

    /**
     * @return Collection
     */
    public function first(): Collection
    {
        return $this->find(0);
    }

    /**
     * @param int $key
     * @return Collection
     */
    public function find(int $key): Collection
    {
        return collect($this->get()->get($key));
    }

    /**
     * @param array $keywords
     * @return array
     */
    private function withData(array $keywords): array
    {
        $array = [];
        foreach ($keywords as $key => $keyword) {
            $arr = match ($key) {
                0 => $this->firstWith($keyword),
                1 => $this->secondWith($keyword),
                2 => $this->thirdWith($keyword),
                3 => ['return' => $keyword],
                5 => $this->sixthWith($keyword),
                default => [''],
            };
            $array = array_merge($array, $arr);
        }
        return $array;
    }

    /**
     * @param string $keyword
     * @return array
     */
    private function firstWith(string $keyword): array
    {
        $keyword = str_replace(['[', ']'], '', trim($keyword));
        [$ip, $user, $time, $timeZone] = explode(' ', $keyword, 4);
        return [
            'ip' => $ip,
            'user' => $user,
            'time' => Carbon::create($time . ' ' . $timeZone)->format('Y-m-d H:i:s')
        ];
    }

    /**
     * @param string $keyword
     * @return array
     */
    private function secondWith(string $keyword): array
    {
        $arr = explode(' ', trim($keyword), 3);
        $data = [
            'method' => $arr[0] ?? $keyword,
            'url' => $arr[1] ?? $keyword,
            'http' => $arr[2] ?? $keyword,
        ];
        $data['is_warning'] = !isset($data['url']) || !(Str::startsWith($data['url'], ['/api', '/static']) || $data['url'] === '/');
        return $data;
    }

    /**
     * @param string $keyword
     * @return array
     */
    private function thirdWith(string $keyword): array
    {
        $arr = explode(' ', trim($keyword), 2);
        return [
            'http_code' => $arr[0] ?? 0,
            'size' => $arr[1] ?? 0,
        ];
    }

    /**
     * @param string $keyword
     * @return array
     */
    private function sixthWith(string $keyword): array
    {
        $agent = new Agent();
        if (!empty($keyword)) {
            $agent->setUserAgent($keyword);
        }
        $array = [
            'user_agent' => $keyword,
            'platform' => $agent->platform(),
            'browser' => $agent->browser(),
            'is_robot' => $agent->isRobot(),
            'is_mobile' => $agent->isMobile(),
        ];
        $array['platform_version'] = $agent->version($array['platform']);
        $array['browser_version'] = $agent->version($array['browser']);
        return $array;
    }
}
